﻿using System.Windows;
using System.Windows.Media.Animation;
using System.ComponentModel;
using System;

namespace MartinsEssentials.Animation
{
    public class ContentTransition : DependencyObject
    {
        #region blend designer fix
        private static bool? _isInDesignMode;
        public static bool IsInDesignModeStatic
        {
            get
            {
                if (!_isInDesignMode.HasValue)
                {
#if SILVERLIGHT
            _isInDesignMode = DesignerProperties.IsInDesignTool;
#else
                    var prop = DesignerProperties.IsInDesignModeProperty;
                    _isInDesignMode
                        = (bool)DependencyPropertyDescriptor
                        .FromProperty(prop, typeof(FrameworkElement))
                        .Metadata.DefaultValue;
#endif
                }

                return _isInDesignMode.Value;
            }
        }
        #endregion

        /**
         * Example
         * 
         * <ListBox ItemsSource="{Binding SelectedItem}" 
         * me:ContentTransition.Property="ItemsSource" 
         * me:ContentTransition.Binding="{Binding SelectedItem}" 
         * me:ContentTransition.FadeInStoryboard="{StaticResource SelectedItemFadeIn}" 
         * me:ContentTransition.FadeOutStoryboard="{StaticResource SelectedItemFadeOut}"/>
         * 
         * */
        public static DependencyProperty BindingProperty = DependencyProperty.RegisterAttached("Binding", typeof(object), typeof(ContentTransition), new PropertyMetadata(BindingChanged));
        public static DependencyProperty PropertyProperty = DependencyProperty.RegisterAttached("Property", typeof(string), typeof(ContentTransition));
        public static DependencyProperty FadeInStoryboard = DependencyProperty.RegisterAttached("FadeInStoryboard", typeof(Storyboard), typeof(ContentTransition));
        public static DependencyProperty FadeOutStoryboard = DependencyProperty.RegisterAttached("FadeOutStoryboard", typeof(Storyboard), typeof(ContentTransition));

        public static readonly RoutedEvent OwnAnimationEvent = EventManager.RegisterRoutedEvent("OwnAnimation", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ContentTransition));

        #region Set & Gets

        public static object GetBinding(DependencyObject e)
        {
            return e.GetValue(BindingProperty);
        }

        public static void SetBinding(DependencyObject e, object value)
        {
            e.SetValue(BindingProperty, value);
        }

        public static string GetProperty(DependencyObject e)
        {
            return (string)e.GetValue(PropertyProperty);
        }

        public static void SetProperty(DependencyObject e, string value)
        {
            e.SetValue(PropertyProperty, value);
        }

        public static Storyboard GetFadeInStoryboard(DependencyObject e)
        {
            return (Storyboard)e.GetValue(FadeInStoryboard);
        }

        public static void SetFadeInStoryboard(DependencyObject e, Storyboard value)
        {
            e.SetValue(FadeInStoryboard, value);
        }

        public static Storyboard GetFadeOutStoryboard(DependencyObject e)
        {
            return (Storyboard)e.GetValue(FadeOutStoryboard);
        }

        public static void SetFadeOutStoryboard(DependencyObject e, Storyboard value)
        {
            e.SetValue(FadeOutStoryboard, value);
        }

        #endregion Set & Gets

        #region adds & removes

        public static void AddOwnAnimationHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.AddHandler(ContentTransition.OwnAnimationEvent, handler);
            }
        }

        public static void RemoveOwnAnimationHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.RemoveHandler(ContentTransition.OwnAnimationEvent, handler);
            }
        }

        #endregion adds & removes

        private static void BindingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            if (IsInDesignModeStatic)
                return;

            FrameworkElement element = dependencyObject as FrameworkElement;

            RoutedEventArgs newEventArgs = new RoutedEventArgs(ContentTransition.OwnAnimationEvent, e.NewValue);
            element.RaiseEvent(newEventArgs);

            if (!newEventArgs.Handled)
            {
                Storyboard fadeOut = GetFadeOutStoryboard(dependencyObject);
                Storyboard fadeIn = GetFadeInStoryboard(dependencyObject);

                if (fadeOut != null)
                {
                    fadeOut.Completed += delegate
                    {
                        dependencyObject.GetType().GetProperty(GetProperty(dependencyObject)).SetValue(dependencyObject, GetBinding(dependencyObject), null);
                        fadeIn.Begin(element);
                    };
                    fadeOut.Begin(element);
                }
                else
                {
                    dependencyObject.GetType().GetProperty(GetProperty(dependencyObject)).SetValue(dependencyObject, GetBinding(dependencyObject), null);
                    fadeIn.Begin(element);
                }
            }
        }
    }
}